package control 
{
	import base.*;
	import base.constants.Events;
	import base.constants.Types;
	import flash.display.Sprite;
	import appkit.responders.NResponder;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.KeyboardEvent;
	import units.assembly.Builder;
	import units.structures.Turret;
	import units.vessels.Vessel;
	
	/*programming 12-4*/
	/*
	 * Not sure of the need for an always-on 
	 * enterframe loop for collision detection etc.
	 * So far for builder-parent hit detection
	 * this is handled internally
	 * */
	public class Manager extends Sprite 
	{
		/* instance variables */
		public var camera:Camera;
		private var statemachine:StateMachine;
		private var list:Vector.<GObject>;
		private var selected:GObject;
		
		
		/* begin mine event */
		private function on_mine(g:GObject):void
		{
			statemachine.changeState(Events.Mine);
		}
		
		/* remove object event */
		private function on_remove(g:GObject):void
		{
			remove(g);
		}
		
		/* insert object event */
		private function on_insert(g:GObject):void
		{
			insert(g);
		}
		
		
		/* enterframe build state */
		private function enterframe_build():void
		{
			/* false = has hit */
			var g:GObject = statemachine.getSelected();
			var hit:Boolean = !list.every( g.everyShape, null);
			g.hitUpdate(hit);
		}
		
		
		/* enterframe main loop */
		private function on_enterframe(e:Event):void
		{
			switch( statemachine.getState())
			{
				/* for the time being, I am assuming that
				 * when the state is Event.Build,
				 * selected is the builder object */
				case Events.Build:
					enterframe_build();
					break;
			}
		}
		
	
		/* receive build order */
		private function on_build(type:Class, father:GObject):void
		{
			statemachine.clearSelected();
			var builder:Builder = new Builder(type, father);
			builder.startBuild();
			insert(builder);
			statemachine.select(builder);
			statemachine.changeState(Events.Build);
		}
		
		/* move selected gObject */
		private function on_selectedmove(g:GObject):void
		{
			/* make sure that the currently selected object
			 * is the one moving */
			if (g == selected)
			{
				statemachine.changeState(Events.Selected_Move);
			}
		}
		
		
		
		/* mouse event handler */
		private function on_mouseclick(e:MouseEvent):void
		{
			switch( statemachine.getState())
			{
				case Events.Free:
					mouseaction_free();
					break;
				
				case Events.Selected:
					mouseaction_selected();
					break;
				
				case Events.Selected_Move:
					mouseaction_selectedmove();
					break;
				
				case Events.Build:
					mouseaction_build();
					break;	
			}
		}
		
		/* mouse handling for build state */
		private function mouseaction_build():void
		{
			/* Again here we are assuming selected is
			 * a builder object, since the build event
			 * sets selected to be so */
			var builder:Builder = statemachine.getSelected() as Builder;
			if ( builder.isValid())
			{
				builder.stopBuild();
				statemachine.clearSelected();
				statemachine.changeState(Events.Free);
			}
		}
		
		/* mouse handling for selected move state */
		private function mouseaction_selectedmove():void
		{
			//(selected as Vessel).add( new GPoint(mouseX, mouseY));
			(statemachine.getSelected() as Vessel).add( new GPoint(mouseX - camera.x, mouseY - camera.y));
			statemachine.clearSelected();
		}
		/* mouse handling for selected state */
		private function mouseaction_selected():void
		{
			if (statemachine.hasSelected())
			{
				if ( !statemachine.getSelected().hitTestPoint(mouseX, mouseY))
					statemachine.clearSelected();
			}
			
		}
		
		/* mouse handling for state free */
		private function mouseaction_free():void
		{
		
		}
		
		/* key event handler */
		private function on_keydown(e:KeyboardEvent):void
		{
			switch( statemachine.getState())
			{
				/* camera handling goes here */
				case Events.Free:
					keyaction_free(e.keyCode);
					break;
					
				/* vessel and structure control goes here */	
				case Events.Selected:
					if (statemachine.hasSelected())
						keyaction_selected(statemachine.getSelected(), e.keyCode);
					break;
			}
		}
		
		/* key handling for state free */
		private function keyaction_free(key:uint):void
		{
			switch(key)
			{
				case 37:
					NResponder.dispatch(Events.Camera_Move, [0]);
					break;
				
				case 38:
					NResponder.dispatch(Events.Camera_Move, [1]);
					break;
				
				case 39:
					NResponder.dispatch(Events.Camera_Move, [2]);
					break;
				
				case 40:
					NResponder.dispatch(Events.Camera_Move, [3]);
					break;
					
				case 86:
					/* v key zoom in - works */
					NResponder.dispatch(Events.Camera_Zoom, [1]);
					break;
					
				case 90:
					/* z key zoomout - doesn't work */
					NResponder.dispatch(Events.Camera_Zoom, [-1]);
					break;
			}
		}
		
		/* key handling for selected vessels and structures */
		private function keyaction_selected(object:GObject, key:uint):void
		{	
			/* for now check to see if it is a vessel but later will have superclass for this */
			if (object.type() == Types.Vessel)
			{
				var actions:Vector.<Action> = (object as Vessel).actions;
				for (var i:uint = 0; i < actions.length; i++)
				{
					/* come up with cleaner system
					 * rather than for loop */
					if (key == actions[i].code)
					{
						actions[i].dispatch();
					}
				}
			}
		}
		
		
		
		
		
		/* del gObject from camera and list */
		public function remove(g:GObject):void
		{
			try
			{
				camera.removeChild(g);
				list.splice(list.indexOf(g), 1);
			}
			catch (err:Error) { }
		}
		
		/* add gObject to camera and list */
		public function insert(g:GObject):void
		{
			list.push(g);
			camera.addChild(g);
		}
		
		/* init variables when added to stage */
		private function init(e:Event):void
		{ 
			/* init variables */
			camera = new Camera();
			list = new Vector.<GObject>();
			addChild(camera);
			statemachine.clearSelected();
		
			/* native event handlers */
			NResponder.addNative(parent, KeyboardEvent.KEY_DOWN, on_keydown);
			NResponder.addNative(parent, MouseEvent.CLICK, on_mouseclick);
			NResponder.addNative(parent, Event.ENTER_FRAME, on_enterframe);
			
			/* game event handlers */
			
			NResponder.add(Events.Selected_Move, on_selectedmove);
			NResponder.add(Events.Build, on_build);
			NResponder.add(Events.Insert, on_insert);
			NResponder.add(Events.Remove, on_remove);
			NResponder.add(Events.Mine, on_mine);
			
			statemachine.changeState(Events.Free);
		}
		
		/* constructor */
		public function Manager() 
		{
			NResponder.addNative(this, Event.ADDED_TO_STAGE, init, 1);
		}
		
	}

}